package validator

import (
	"context"
	"fmt"
	"github.com/go-playground/locales/en"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	enTranslations "github.com/go-playground/validator/v10/translations/en"
	zhTranslations "github.com/go-playground/validator/v10/translations/zh"
	"github.com/pkg/errors"
	"go-zero-demo/common/global"
	"reflect"
	"regexp"
	"strings"
)

// Func 自定义Validator.ValidateMobile
type Func func(fl validator.FieldLevel) bool

// registerValidatorFunc 注册自定义校验tag
func registerValidatorFunc(v *validator.Validate, tag string, msgStr string, fn Func) {
	// 注册tag自定义校验
	_ = v.RegisterValidation(tag, validator.Func(fn))
	//自定义错误内容
	_ = v.RegisterTranslation(tag, global.Trans, func(ut ut.Translator) error {
		// see universal-translator for details
		return ut.Add(tag, "{0}"+msgStr, true)
	}, func(ut ut.Translator, fe validator.FieldError) string {
		t, _ := ut.T(tag, fe.Field())
		return t
	})

	return
}

// Validate 参数校验
// 参考 http://www.findme.wang/blog/detail/category/64/id/733.html
func Validate(ctx context.Context, req interface{}, locale string) error {
	validate := validator.New()
	validate.RegisterTagNameFunc(func(field reflect.StructField) string {
		name := strings.SplitN(field.Tag.Get("json"), ",", 2)[0]
		if name == "-" {
			return ""
		}
		return name
	})
	//中文翻译器
	zhT := zh.New()
	//英文翻译器
	enT := en.New()
	//第一个参数是备用的语言环境，后面的参数是应该支持的语言环境
	uni := ut.New(enT, zhT, enT)
	ok := false
	global.Trans, ok = uni.GetTranslator(locale)
	if !ok {
		return errors.New(fmt.Sprintf("uni.GetTranslator(%s) error", locale))
	}
	switch locale {
	case "en":
		_ = enTranslations.RegisterDefaultTranslations(validate, global.Trans)
	case "zh":
		_ = zhTranslations.RegisterDefaultTranslations(validate, global.Trans)
	default:
		_ = enTranslations.RegisterDefaultTranslations(validate, global.Trans)
	}

	err := validate.StructCtx(ctx, req)
	if err != nil {
		validationErrors := err.(validator.ValidationErrors)
		for _, e := range validationErrors {
			return errors.New(e.Translate(global.Trans))
		}
	}
	// 注册自定义tag
	registerValidatorFunc(validate, "mobile", "手机号非法", ValidateMobile)
	return nil
}

// ValidateMobile 校验手机号
func ValidateMobile(fl validator.FieldLevel) bool {
	// 利用反射拿到结构体tag含有mobile的key字段
	mobile := fl.Field().String()
	//使用正则表达式判断是否合法
	ok, _ := regexp.MatchString(`^1([38][0-9]|14[579]|5[^4]|16[6]|7[1-35-8]|9[189])\d{8}$`, mobile)
	if !ok {
		return false
	}
	return true
}
